package com.yuyou.fn.analyze.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.github.wens.mybatisplus.plugins.Page;
import com.yuyou.fn.analyze.entity.MainAccountTarget;
import com.yuyou.fn.analyze.entity.ProductTarget;
import com.yuyou.fn.analyze.service.*;
import com.yuyou.fn.analyze.vo.*;
import com.yuyou.fn.common.constant.ReportResourceEnum;
import com.yuyou.fn.common.exception.BusException;
import com.yuyou.fn.common.util.BeanUtils;
import com.yuyou.fn.common.util.BigDecimals;
import com.yuyou.fn.common.util.TimeUtils;
import com.yuyou.fn.common.util.Utils;
import com.yuyou.fn.educational.entity.*;
import com.yuyou.fn.educational.service.*;
import com.yuyou.fn.educational.vo.BusTeamPeriodGradeClassNumVo;
import com.yuyou.fn.educational.vo.CourseClassQueryVo;
import com.yuyou.fn.educational.vo.PeriodSeqStepSituationVo;
import com.yuyou.fn.educational.vo.SimpleQueryVo;
import com.yuyou.fn.platform.entity.AreaTeam;
import com.yuyou.fn.platform.entity.BusTeam;
import com.yuyou.fn.platform.entity.SysUser;
import com.yuyou.fn.platform.permission.DataPermission;
import com.yuyou.fn.platform.service.IAreaTeamService;
import com.yuyou.fn.platform.service.IBusTeamService;
import com.yuyou.fn.platform.service.ISysDataPermissionService;
import com.yuyou.fn.report.entity.MergeStudentRegDetail;
import com.yuyou.fn.report.service.ICostOfProductService;
import com.yuyou.fn.report.service.IRealIncomeOfClassService;
import com.yuyou.fn.report.service.IMergeStudentRegDetailService;
import com.yuyou.fn.report.vo.*;
import com.yuyou.fn.settlement.entity.MainAccount;
import com.yuyou.fn.settlement.service.IChangeRecordService;
import com.yuyou.fn.settlement.service.IMainAccountService;
import com.yuyou.fn.settlement.vo.ChangeRecordQueryVo;
import com.yuyou.fn.settlement.vo.MainAccountTimeAmountVo;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.streaming.SXSSFCell;
import org.apache.poi.xssf.streaming.SXSSFRow;
import org.apache.poi.xssf.streaming.SXSSFSheet;
import org.apache.poi.xssf.streaming.SXSSFWorkbook;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.data.redis.core.HashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.*;

/**
 * ProductTarget 表数据服务层接口实现类
 */
@Service
public class DataStatistsServiceImpl implements IDataStatisticsService {

    private static final String FULLCLASS_FORBID_SETTING = "fullclass:forbid:setting:%d";

    @Resource
    private IBusinessStatisticsService businessStatisticsService;

    @Resource
    private IProductStatisticsService productStatisticsService;

    @Resource
    private IBusTeamService busTeamService;


    @Resource
    private IMainAccountService mainAccountService;

    @Resource
    private IProductService productService;

    @Resource
    private IPeriodService periodService;

    @Resource
    private IMainAccountTargetService mainAccountTargetService;

    @Resource
    private IProductTargetService productTargetService;

    @Resource
    private ICourseClassService courseClassService;


    @Resource
    private IBaseGradeService baseGradeService;

    @Resource
    private IChangeRecordService changeRecordService;

    @Resource
    private ISysDataPermissionService sysDataPermissionService;


    @Resource
    private ICostOfProductService costOfProductService;

    @Resource
    private IRealIncomeOfClassService realIncomeOfClassService;


    @Resource
    private IMergeStudentRegDetailService mergeStudentRegDetailService;


    @Resource
    private IAreaTeamService areaTeamService;

    @Resource
    private RedisTemplate<String,String> redisTemplate;

    @Resource
    private IIndexStatisticsService indexStatisticsService;

    @Resource
    private IPeriodSegmentService periodSegmentService;

    @Resource
    private IRoomService roomService;

    @Override
    public TeacherContinueReadVo findTeacherContinueRead(Long teacherId, Long periodId, Integer bigLectureNum) {
        PeriodSeqStepSituationVo periodSeqStepSituationVo=periodService.findPeriodSeqStepSituation(Arrays.asList(periodId));
        Map<Long,List<Long>> seqMap=periodSeqStepSituationVo.getSeqMap();
        Map<Long,List<Long>> stepMap=periodSeqStepSituationVo.getStepMap();
        List<Long> seqStepList=periodSeqStepSituationVo.getSeqStepList();
        List<Long> allPeriodIds = periodSeqStepSituationVo.getAllPeriodIds();
        Map<Long,Map<Integer,PeriodSegment>> periodSegmentMap=periodSeqStepSituationVo.getPeriodSegmentMap();

        List<Long> seqIdList=seqMap.get(periodId);
        List<Long> stepIdList=stepMap.get(periodId);


        PeriodQueryRegVo periodQueryRegVo=new PeriodQueryRegVo();
        periodQueryRegVo.setRegStatus(0);
        periodQueryRegVo.setTeacherIds(Arrays.asList(teacherId));
        periodQueryRegVo.setPeriodIds(Arrays.asList(periodId));
        //periodQueryRegVo.setLectureNum(bigLectureNum);
        periodQueryRegVo.setChargingStatus(2);

        RegRelativceQueryVo regRelativceQueryVo=new RegRelativceQueryVo();
        regRelativceQueryVo.setRecordChargingStatus(2);
        //regRelativceQueryVo.setBigRecordLectureNum(bigLectureNum);
        regRelativceQueryVo.setNeedSameSubject(1);
        regRelativceQueryVo.setPeriodIds(seqStepList);

        List<RegRelativeVo> regRelativeVoList=mergeStudentRegDetailService.queryRegRelative(periodQueryRegVo,regRelativceQueryVo);
        regRelativeVoList=mergeStudentRegDetailService.filterListByEffectiveLectureNum(regRelativeVoList,periodSegmentMap);
        regRelativeVoList=mergeStudentRegDetailService.filterListByReportConfig(allPeriodIds,regRelativeVoList, ReportResourceEnum.薪酬教师续读.id);

        Map<Long, List<RegRelativeVo>> classRegMap =new HashMap<>();
        for (RegRelativeVo regRelativeVo:regRelativeVoList){
            Long classId=regRelativeVo.getClassId();
            List<RegRelativeVo> list=classRegMap.get(classId);
            if (list==null){
                list=new ArrayList<>();
                classRegMap.put(classId,list);
            }
            list.add(regRelativeVo);
        }

        TeacherContinueReadVo teacherContinueReadVo = new TeacherContinueReadVo();
        Integer unContinueNum = 0;
        Integer sequentialNum = 0;
        Integer stepNum = 0;
        Integer dateNum = 0;
        List<ClassContinueRate> classContinueRateList = new ArrayList<>();
        Period nextPeriod = periodService.findNextPeriod(periodId);
        if (nextPeriod != null) {
            dateNum = TimeUtils.daysOfTwo(TimeUtils.now(), nextPeriod.getStartDate()) + 1;
        }
        teacherContinueReadVo.setDateNum(dateNum);
        for (Map.Entry<Long,List<RegRelativeVo>> entry : classRegMap.entrySet()){
            Long classId=entry.getKey();
            ClassContinueRate classContinueRate = new ClassContinueRate();
            classContinueRate.setClassId(classId);
            List<RegRelativeVo> regRelativeVos=entry.getValue();
            Set<Long> nowStudentIdSet=new HashSet<>();
            Set<Long> seqStudentIdSet=new HashSet<>();
            Set<Long> stepStudentIdSet=new HashSet<>();
            Set<Long> seqStepStudentIdSet=new HashSet<>();
            for (RegRelativeVo regRelativeVo:regRelativeVos){
                Long relativeRegId=regRelativeVo.getRelativeRegId();
                Long relativePeriodId=regRelativeVo.getRelativePeriodId();
                Long studentId=regRelativeVo.getStudentId();
                nowStudentIdSet.add(studentId);
                classContinueRate.setClassName(regRelativeVo.getClassName());
                if (regRelativeVo.getRelativeRegId()==null){
                    continue;
                }
                if (seqIdList!=null && seqIdList.contains(relativePeriodId)){
                    seqStudentIdSet.add(studentId);
                    seqStepStudentIdSet.add(studentId);
                }
                if (stepIdList!=null && stepIdList.contains(relativePeriodId)){
                    stepStudentIdSet.add(studentId);
                    seqStepStudentIdSet.add(studentId);
                }
            }
            classContinueRate.setNowPeriodNum(nowStudentIdSet.size());
            teacherContinueReadVo.setNowPeriodNum(teacherContinueReadVo.getNowPeriodNum()+nowStudentIdSet.size());


            classContinueRate.setSequentialNum(seqStudentIdSet.size());
            classContinueRate.setSequentialRate(Utils.getPercent(seqStudentIdSet.size()+"", classContinueRate.getNowPeriodNum().toString(), 2));
            classContinueRate.setStepNum(stepStudentIdSet.size());
            classContinueRate.setStepRate(Utils.getPercent(stepStudentIdSet.size()+"", classContinueRate.getNowPeriodNum().toString(), 2));
            classContinueRateList.add(classContinueRate);

            unContinueNum=unContinueNum+nowStudentIdSet.size()-seqStepStudentIdSet.size();
            sequentialNum=sequentialNum+seqStudentIdSet.size();
            stepNum=stepStudentIdSet.size()+stepNum;
        }

        teacherContinueReadVo.setSequentialNum(sequentialNum);
        teacherContinueReadVo.setSequentialRate(Utils.getPercent(sequentialNum.toString(), teacherContinueReadVo.getNowPeriodNum().toString(), 2));
        teacherContinueReadVo.setStepNum(stepNum);
        teacherContinueReadVo.setStepRate(Utils.getPercent(stepNum.toString(), teacherContinueReadVo.getNowPeriodNum().toString(), 2));
        teacherContinueReadVo.setUnContinueNum(unContinueNum);
        teacherContinueReadVo.setClassContinueRateList(classContinueRateList);
        return teacherContinueReadVo;
    }



    @Override
    public List<StudentReadState> findSeniorStudentReadState(Long seniorId, Long periodId) {

        PeriodSeqStepSituationVo periodSeqStepSituationVo=periodService.findPeriodSeqStepSituation(Arrays.asList(periodId));
        Map<Long,List<Long>> seqMap=periodSeqStepSituationVo.getSeqMap();
        Map<Long,List<Long>> stepMap=periodSeqStepSituationVo.getStepMap();
        List<Long> seqStepList=periodSeqStepSituationVo.getSeqStepList();
        Map<Long,Map<Integer,PeriodSegment>> periodSegmentMap=periodSeqStepSituationVo.getPeriodSegmentMap();
        List<Long> seqIdList=seqMap.get(periodId);
        List<Long> stepIdList=stepMap.get(periodId);
        List<Long> allPeriodIds = periodSeqStepSituationVo.getAllPeriodIds();

        PeriodQueryRegVo periodQueryRegVo=new PeriodQueryRegVo();
        periodQueryRegVo.setRegStatus(0);
        periodQueryRegVo.setPeriodIds(Arrays.asList(periodId));
        periodQueryRegVo.setSeniorIds(Arrays.asList(seniorId));
        //periodQueryRegVo.setLectureNum(5);
        periodQueryRegVo.setChargingStatus(2);
        RegRelativceQueryVo regRelativceQueryVo=new RegRelativceQueryVo();
        regRelativceQueryVo.setRecordChargingStatus(2);
        //regRelativceQueryVo.setBigRecordLectureNum(5);
        regRelativceQueryVo.setPeriodIds(seqStepList);
        regRelativceQueryVo.setNeedSameSubject(1);

        List<RegRelativeVo> regRelativeVoList=mergeStudentRegDetailService.queryRegRelative(periodQueryRegVo,regRelativceQueryVo);
        regRelativeVoList=mergeStudentRegDetailService.filterListByEffectiveLectureNum(regRelativeVoList,periodSegmentMap);
        regRelativeVoList=mergeStudentRegDetailService.filterListByReportConfig(allPeriodIds,regRelativeVoList,ReportResourceEnum.营运班主任续读.id);

        return toStudentReadState(regRelativeVoList,seqIdList,stepIdList);
    }


    private List<StudentReadState> toStudentReadState( List<RegRelativeVo> regRelativeVoList,List<Long> seqIdList,List<Long> stepIdList) {

        Map<Long,List<RegRelativeVo>> map=BeanUtils.toGroup(regRelativeVoList,"studentId");
        Map<String,StudentReadState> studentMap=new HashMap<>();
        for (Map.Entry<Long,List<RegRelativeVo>> entry:map.entrySet()){
            Long studentId=entry.getKey();
            List<RegRelativeVo> oneStudentregRelativeVoList=entry.getValue();
            for (RegRelativeVo regRelativeVo:oneStudentregRelativeVoList){
                String key=regRelativeVo.getClassId()+"_"+studentId;
                StudentReadState studentReadState=studentMap.get(key);

                Long relativePeriodId=regRelativeVo.getRelativePeriodId();
                Long relativeRegId=regRelativeVo.getRelativeRegId();
                if (studentReadState==null){
                    studentReadState = new StudentReadState();
                    studentReadState.setClassId(regRelativeVo.getClassId());
                    studentReadState.setClassName(regRelativeVo.getClassName());
                    studentReadState.setStudentId(regRelativeVo.getStudentId());
                    studentReadState.setStudentName(regRelativeVo.getStudentName());
                    studentReadState.setIfSequential(0);
                    studentReadState.setIfStep(0);
                }

                if (relativeRegId!=null){
                    if (seqIdList!=null && seqIdList.contains(relativePeriodId)){
                        studentReadState.setIfSequential(1);
                    }
                    if (stepIdList!=null && stepIdList.contains(relativePeriodId)){
                        studentReadState.setIfStep(1);
                    }
                }
                studentMap.put(key,studentReadState);
            }

        }
        Collection<StudentReadState> studentReadStateCollection=studentMap.values();
        List<StudentReadState> studentReadStateList = new ArrayList<>(studentReadStateCollection);

        return studentReadStateList;
    }



    @Override
    public List<StudentReadState> findStudentReadState(Long teacherId, Long classId) {
        CourseClass courseClass=courseClassService.findById(classId);
        Long periodId=courseClass.getPeriodId();
        PeriodSeqStepSituationVo periodSeqStepSituationVo=periodService.findPeriodSeqStepSituation(Arrays.asList(periodId));
        Map<Long,List<Long>> seqMap=periodSeqStepSituationVo.getSeqMap();
        Map<Long,List<Long>> stepMap=periodSeqStepSituationVo.getStepMap();
        List<Long> seqStepList=periodSeqStepSituationVo.getSeqStepList();
        List<Long> allPeriodIds = periodSeqStepSituationVo.getAllPeriodIds();
        Map<Long,Map<Integer,PeriodSegment>> periodSegmentMap=periodSeqStepSituationVo.getPeriodSegmentMap();

        List<Long> seqIdList=seqMap.get(periodId);
        List<Long> stepIdList=stepMap.get(periodId);


        PeriodQueryRegVo periodQueryRegVo=new PeriodQueryRegVo();
        periodQueryRegVo.setRegStatus(0);
        periodQueryRegVo.setClassIds(Arrays.asList(classId));

        periodQueryRegVo.setChargingStatus(2);
        RegRelativceQueryVo regRelativceQueryVo=new RegRelativceQueryVo();
        regRelativceQueryVo.setRecordChargingStatus(2);
        regRelativceQueryVo.setPeriodIds(seqStepList);
        regRelativceQueryVo.setNeedSameSubject(1);

        List<RegRelativeVo> regRelativeVoList=mergeStudentRegDetailService.queryRegRelative(periodQueryRegVo,regRelativceQueryVo);
        regRelativeVoList=mergeStudentRegDetailService.filterListByEffectiveLectureNum(regRelativeVoList,periodSegmentMap);
        regRelativeVoList=mergeStudentRegDetailService.filterListByReportConfig(allPeriodIds,regRelativeVoList,ReportResourceEnum.薪酬教师续读.id);

        return toStudentReadState(regRelativeVoList,seqIdList,stepIdList);
    }

    @Override
    public ClassStudentReadState findClassStudentReadState(Long teacherId, Long classId, Integer bigLectureNum) {
        ClassStudentReadState classStudentReadState = new ClassStudentReadState();
        CourseClass courseClass = courseClassService.findById(classId, "className", "campusName", "periodName");
        BeanUtils.copyProperties(classStudentReadState, courseClass);
        List<StudentReadState> studentReadStateList = this.findStudentReadState(teacherId, classId);
        classStudentReadState.setStudentReadStateList(studentReadStateList);
        return classStudentReadState;
    }

    @Override
    public List<MainAccount> findByAreaTeamId(List<Long> areaTeamIds, Long userId) {
        List<Long> mainAccountIds = new ArrayList<>();
        mainAccountIds.addAll(areaTeamIds);
        mainAccountIds.addAll(this.findPermissionBusTeam(areaTeamIds, userId));
        List<MainAccount> mainAccountList = mainAccountService.findByIds(mainAccountIds);
        return mainAccountList;
    }

    @Override
    public List<Long> findPermissionBusTeam(List<Long> areaTeamIds, Long userId) {
        List<BusTeam> busTeamList = busTeamService.findBusTeamByAreaTeamIds(areaTeamIds);
        List<Long> busTeamIds = BeanUtils.toList(busTeamList, "busTeamId");
        busTeamIds = this.filterBusTeamByPermissions(busTeamIds, userId);
        return busTeamIds;
    }

    @Override
    public List<Long> filterBusTeamByPermissions(List<Long> busTeamIdList, Long userId) {
        if (busTeamIdList == null || busTeamIdList.size() <= 0) {
            return Collections.EMPTY_LIST;
        }
        DataPermission dataPermission = sysDataPermissionService.findDataPermissionForUser(userId);
        List<Long> permissionBusTeamIdList = dataPermission.getBusTeamIds();
        busTeamIdList.retainAll(permissionBusTeamIdList);
        return busTeamIdList;
    }

    @Override
    public Map<String, List<DataVo>> findBusTeamByAreaTeamId(Long areaTeamId, Date startDate, Date endDate) {
        if (startDate.getTime() > endDate.getTime()) {
            throw new BusException("开始时间必须小于等于结束时间");
        }
        Map<String, List<DataVo>> resultMap = new HashMap<String, List<DataVo>>();
        List<BusTeam> busTeamList = busTeamService.findBusTeamByAreaTeamIds(Arrays.asList(areaTeamId));
        List<Long> busTeamIdList = BeanUtils.toList(busTeamList, "busTeamId");
        busTeamIdList = productStatisticsService.filterBusTeamByPermissions(busTeamIdList);
        List<MainAccount> mainAccountList = mainAccountService.findByIds(busTeamIdList);
        List<MainAccountCostAndIncome> mainAccountCostAndIncomeList = businessStatisticsService.findMainAccountCostAndIncome(startDate, endDate, mainAccountList);
        List<DataVo> busTeamIncomeList = new ArrayList<DataVo>(mainAccountCostAndIncomeList.size());
        List<DataVo> busTeamProfitList = new ArrayList<DataVo>(mainAccountCostAndIncomeList.size());
        for (MainAccountCostAndIncome mainAccountCostAndIncome : mainAccountCostAndIncomeList) {
            DataVo income = new DataVo();
            DataVo profit = new DataVo();
            income.setName(mainAccountCostAndIncome.getName());
            income.setValue(BigDecimals.toFixed2(mainAccountCostAndIncome.getIncome(), 2));
            profit.setName(mainAccountCostAndIncome.getName());
            profit.setValue(BigDecimals.toFixed2(mainAccountCostAndIncome.getProfits(), 2));
            busTeamIncomeList.add(income);
            busTeamProfitList.add(profit);
        }
        resultMap.put("busTeamIncomeList", busTeamIncomeList);
        resultMap.put("busTeamProfitList", busTeamProfitList);

        return resultMap;
    }



    @Override
    public Map<String, List<DataVo>> findProductByAreaTeamId(Long areaTeamId, Date startDate, Date endDate, SysUser sysUser) {
        if (startDate.getTime() > endDate.getTime()) {
            throw new BusException("开始时间必须小于等于结束时间");
        }
        Map<String, List<DataVo>> resultMap = new HashMap<String, List<DataVo>>();
        List<Product> productList = productService.findBaseProductByAreaTeamId(areaTeamId);
        List<ProductCostAndIncomeVo> productCostAndIncomeVoList = productStatisticsService.findProductCostAndIncome(Arrays.asList(areaTeamId), startDate, endDate, productList, sysUser);
        List<DataVo> productIncomeList = new ArrayList<DataVo>(productCostAndIncomeVoList.size());
        List<DataVo> productProfitList = new ArrayList<DataVo>(productCostAndIncomeVoList.size());
        for (ProductCostAndIncomeVo productCostAndIncomeVo : productCostAndIncomeVoList) {
            DataVo income = new DataVo();
            DataVo profit = new DataVo();

            income.setName(productCostAndIncomeVo.getProductName());
            income.setValue(BigDecimals.toFixed2(productCostAndIncomeVo.getIncome(), 2));
            profit.setName(productCostAndIncomeVo.getProductName());
            profit.setValue(BigDecimals.toFixed2(productCostAndIncomeVo.getProfits(), 2));
            productIncomeList.add(income);
            productProfitList.add(profit);
        }
        resultMap.put("productIncomeList", productIncomeList);
        resultMap.put("productProfitList", productProfitList);
        return resultMap;
    }

    @Override
    public RecentDetailVo findBusTeamRecentDetail(Long areaTeamId, Date date, int monthNum) {
        date = Utils.parseDate(Utils.formatDate(date, "yyyy-MM"), "yyyy-MM");
        RecentDetailVo recentDetailVo = new RecentDetailVo();
        List<BusTeam> busTeamList = busTeamService.findBusTeamByAreaTeamIds(Arrays.asList(areaTeamId));
        List<Long> busTeamIdList = BeanUtils.toList(busTeamList, "busTeamId");
        busTeamIdList = productStatisticsService.filterBusTeamByPermissions(busTeamIdList);
        List<Date> dateList = new ArrayList<Date>(monthNum);
        List<BigDecimal> costList = new ArrayList<BigDecimal>(monthNum);
        List<BigDecimal> incomeList = new ArrayList<BigDecimal>(monthNum);
        List<BigDecimal> profitsList = new ArrayList<BigDecimal>(monthNum);
        Date startDate = TimeUtils.addMonthByNum(date, -monthNum);
        Date endDate = TimeUtils.addMonthByNum(date, -1);
        endDate = TimeUtils.lastDateOfMonth(endDate);

        ChangeRecordQueryVo changeRecordQueryVo=new ChangeRecordQueryVo();
        changeRecordQueryVo.setDirection(0);
        changeRecordQueryVo.setStartDate(startDate);
        changeRecordQueryVo.setEndDate(endDate);
        changeRecordQueryVo.setSubjects(Arrays.asList("real_income","cost"));
        changeRecordQueryVo.setMainAccountIds(busTeamIdList);
        List<MainAccountTimeAmountVo> mainAccountTimeAmountVoList=changeRecordService.findMonthAmount(changeRecordQueryVo);
        Map<String,List<MainAccountTimeAmountVo>> map=BeanUtils.toGroup(mainAccountTimeAmountVoList,"effectTime");

        for (int i = monthNum; i > 0; i--) {

            BigDecimal cost = BigDecimal.ZERO;
            BigDecimal profits = null;
            BigDecimal income = BigDecimal.ZERO;
            Date newDate = TimeUtils.addMonthByNum(date, -i);
            dateList.add(newDate);
            String effectTime=Utils.formatDate(newDate,"yyyy-MM");
            List<MainAccountTimeAmountVo> one=map.get(effectTime);
            if (one!=null){
                for (MainAccountTimeAmountVo mainAccountTimeAmountVo:one){
                    if ("cost".equals(mainAccountTimeAmountVo.getSubject())){
                        cost=cost.add(mainAccountTimeAmountVo.getAmount());
                    }else if ("real_income".equals(mainAccountTimeAmountVo.getSubject())){
                        income=income.add(mainAccountTimeAmountVo.getAmount());
                    }
                }
            }

            profits = income.subtract(cost);
            incomeList.add(BigDecimals.toFixed2(income, 2));
            profitsList.add(BigDecimals.toFixed2(profits, 2));
            costList.add(BigDecimals.toFixed2(cost, 2));
        }
        recentDetailVo.setDateList(dateList);
        recentDetailVo.setCostList(costList);
        recentDetailVo.setIncomeList(incomeList);
        recentDetailVo.setProfitList(profitsList);
        return recentDetailVo;
    }


    @Override
    public RecentDetailVo findProdcutRecentDetail(Long areaTeamId, Date date, int monthNum, SysUser sysUser) {
        date = Utils.parseDate(Utils.formatDate(date, "yyyy-MM"), "yyyy-MM");
        RecentDetailVo recentDetailVo = new RecentDetailVo();
        Date startDate = TimeUtils.addMonthByNum(date, -monthNum);
        Date endDate = TimeUtils.addMonthByNum(date, -1);
        endDate = TimeUtils.lastDateOfMonth(endDate);
        List<Long> busTeamIds = this.findPermissionBusTeam(Arrays.asList(areaTeamId), sysUser.getUserId());
        List<Product> productList = productService.findBaseProductByAreaTeamId(areaTeamId);
        List<Long> productIds = BeanUtils.toList(productList, "productId");
        CostOfProductQueryVo costOfProductQueryVo=new CostOfProductQueryVo();
        costOfProductQueryVo.setMainAccountIds(busTeamIds);
        costOfProductQueryVo.setProductIds(productIds);
        costOfProductQueryVo.setEndDate(endDate);
        costOfProductQueryVo.setStartDate(startDate);
        List<TimeAmountVo> costOfProductList=costOfProductService.findProductMonthAmount(costOfProductQueryVo);
        Map<String,TimeAmountVo>  costOfProductMap=BeanUtils.toMap(costOfProductList,"effectTime");

        RealIncomeClassQueryVo realIncomeClassQueryVo=new RealIncomeClassQueryVo();
        realIncomeClassQueryVo.setBusTeamIds(busTeamIds);
        realIncomeClassQueryVo.setProductIds(productIds);
        realIncomeClassQueryVo.setEndDate(endDate);
        realIncomeClassQueryVo.setStartDate(startDate);
        List<TimeAmountVo> realIncomeOfClassList = realIncomeOfClassService.findClassTimeAmount(realIncomeClassQueryVo);
        Map<String,TimeAmountVo>  realIncomeOfClassMap=BeanUtils.toMap(realIncomeOfClassList,"effectTime");

        List<Date> dateList = new ArrayList<Date>(monthNum);
        List<BigDecimal> costList = new ArrayList<BigDecimal>(monthNum);
        List<BigDecimal> incomeList = new ArrayList<BigDecimal>(monthNum);
        List<BigDecimal> profitsList = new ArrayList<BigDecimal>(monthNum);


        for (int i = monthNum; i > 0; i--) {
            BigDecimal cost = BigDecimal.ZERO;
            BigDecimal profits = null;
            BigDecimal income = BigDecimal.ZERO;
            Date newDate = TimeUtils.addMonthByNum(date, -i);
            dateList.add(newDate);
            String key=Utils.formatDate(newDate,"yyyy-MM");
            TimeAmountVo costTimeAmountVo=costOfProductMap.get(key);
            if (costTimeAmountVo!=null && costTimeAmountVo.getAmount()!=null){
                cost=costTimeAmountVo.getAmount();
            }

            TimeAmountVo incomeTimeAmountVo=realIncomeOfClassMap.get(key);
            if (incomeTimeAmountVo!=null && incomeTimeAmountVo.getAmount()!=null){
                income=incomeTimeAmountVo.getAmount();
            }


            profits = income.subtract(cost);
            incomeList.add(BigDecimals.toFixed2(income, 2));
            profitsList.add(BigDecimals.toFixed2(profits, 2));
            costList.add(BigDecimals.toFixed2(cost, 2));
        }
        recentDetailVo.setDateList(dateList);
        recentDetailVo.setCostList(costList);
        recentDetailVo.setIncomeList(incomeList);
        recentDetailVo.setProfitList(profitsList);
        return recentDetailVo;
    }

    @Override
    public List<MainAccountCostAndIncome> findBusTeamTargetAndReal(Long areaTeamId, Long periodId) {
        Period period = periodService.findById(periodId);
        List<BusTeam> busTeamList = busTeamService.findBusTeamByAreaTeamIds(Arrays.asList(areaTeamId));
        List<Long> busTeamIdList = BeanUtils.toList(busTeamList, "busTeamId");
        busTeamIdList = productStatisticsService.filterBusTeamByPermissions(busTeamIdList);
        List<MainAccount> mainAccountList = mainAccountService.findByIds(busTeamIdList);
        List<MainAccountTarget> mainAccountTargetList = mainAccountTargetService.findListByMainAccountIdsAndPeriodIdAndTargetTypes(busTeamIdList, periodId, Arrays.asList("0","1"));
        List<MainAccountCostAndIncome> mainAccountCostAndIncomeList = businessStatisticsService.findMainAccountCostAndIncome(period.getStartDate(), TimeUtils.changeOneDateLastTime(period.getEndDate()), mainAccountList);
        for (MainAccountCostAndIncome mainAccountCostAndIncome : mainAccountCostAndIncomeList) {
            for (MainAccountTarget mainAccountTarget : mainAccountTargetList) {
                if (mainAccountCostAndIncome.getMainAcoountId().equals(mainAccountTarget.getMainAccountId())) {
                    if ("0".equals(mainAccountTarget.getTargetType())) {
                        mainAccountCostAndIncome.setTargetIncome(mainAccountTarget.getTargetNum());
                    } else if ("1".equals(mainAccountTarget.getTargetType())) {
                        mainAccountCostAndIncome.setTargetProfits(mainAccountTarget.getTargetNum());
                    }
                }
            }
        }
        return mainAccountCostAndIncomeList;
    }


    @Override
    public List<ProductCostAndIncomeVo> findProductTargetAndReal(Long areaTeamId, Long periodId, SysUser sysUser) {
        List<Product> productList = productService.findBaseProductByAreaTeamId(areaTeamId);
        Period period = periodService.findById(periodId);
        List<Long> prodcutIdList = BeanUtils.toList(productList, "productId");
        List<ProductTarget> productTargetList = productTargetService.findListByProductIdsAndPeriodIds(prodcutIdList, Arrays.asList(periodId), null, null);
        List<ProductCostAndIncomeVo> productCostAndIncomeVoList = productStatisticsService.findProductCostAndIncome(Arrays.asList(areaTeamId), period.getStartDate(), TimeUtils.changeOneDateLastTime(period.getEndDate()), productList, sysUser);
        for (ProductCostAndIncomeVo productCostAndIncomeVo : productCostAndIncomeVoList) {
            for (ProductTarget productTarget : productTargetList) {
                if (productTarget.getProductId().equals(productCostAndIncomeVo.getProductId())) {
                    if (productTarget.getTargetType() == 0) {
                        productCostAndIncomeVo.setTargetIncome(productTarget.getTargetPrice());
                    } else if (productTarget.getTargetType() == 1) {
                        productCostAndIncomeVo.setTargetProfits(productTarget.getTargetPrice());
                    }
                }
            }
        }
        return productCostAndIncomeVoList;
    }

    @Override
    public Map<String, List<FullClassRate>> findFullRate(Long areaTeamId, Long periodId, Long userId) {
        Map<String, List<FullClassRate>> resultMap = new HashMap<String, List<FullClassRate>>();
        List<FullClassRate> gradeFullClassRateList = new ArrayList<>();
        List<FullClassRate> productFullClassRateList = new ArrayList<>();
        //Period period=periodService.findById(periodId);
        List<Long> busTeamIdList = this.findPermissionBusTeam(Arrays.asList(areaTeamId), userId);
        List<CourseClass> courseClassList = courseClassService.findSimpByBusTeamIdsAndPeriodId(busTeamIdList, periodId, "classId", "gradeId", "subjectId", "quota", "lectureAmount");
        PeriodQueryRegVo periodQueryRegVo=new PeriodQueryRegVo();
        periodQueryRegVo.setLectureNum(5);
        periodQueryRegVo.setRegStatus(0);
        List<MergeStudentRegDetail> mergeStudentRegDetailList =mergeStudentRegDetailService.findListByBusTeamIdsPeriodsGradeIds(busTeamIdList,Arrays.asList(periodId),null,periodQueryRegVo,"classId","periodId");
        Map<Long,List<MergeStudentRegDetail>> regMap=BeanUtils.toGroup(mergeStudentRegDetailList,"classId");
        Map<Long, Integer> map=new HashMap<>();
        for (Map.Entry<Long,List<MergeStudentRegDetail>> entry:regMap.entrySet()){
            Long key=entry.getKey();
            map.put(key,entry.getValue().size());
        }



        List<BaseGrade> baseGradeList = baseGradeService.findAllFromCache();
        DecimalFormat df = new DecimalFormat("0.00");
        for (BaseGrade baseGrade : baseGradeList) {
            FullClassRate fullClassRate = new FullClassRate();
            fullClassRate.setId(baseGrade.getGradeId());
            fullClassRate.setName(baseGrade.getGradeName());
            Integer all = 0;
            Integer sub = 0;
            for (CourseClass courseClass : courseClassList) {
                Integer regNum = map.get(courseClass.getClassId());
                all = all + courseClass.getQuota();
                if (regNum != null && courseClass.getGradeId().equals(baseGrade.getGradeId())) {
                    sub = sub + regNum;
                }
            }
            if (all == 0) continue;
            double rate = Double.parseDouble(df.format(((double) sub / (double) all * 100)));

            if (sub > 0) {
                fullClassRate.setAll(all);
                fullClassRate.setSub(sub);
                fullClassRate.setRate(rate);
                gradeFullClassRateList.add(fullClassRate);
            }
        }

        List<Product> productList = productService.findBaseProductByAreaTeamId(areaTeamId);
        List<Long> productIdList = BeanUtils.toList(productList, "productId");

        List<CourseClass> productClass = courseClassService.findSimpByProductIdsAndBusTeamIdsAndPeriodId(productIdList, busTeamIdList, periodId, "classId", "className", "quota", "productId", "lectureAmount");
        Map<Long, List<CourseClass>> productClassMap = BeanUtils.toGroup(productClass, "productId");

        for (Product product : productList) {
            FullClassRate fullClassRate = new FullClassRate();
            fullClassRate.setName(product.getName());
            fullClassRate.setId(product.getProductId());
            Integer all = 0;
            Integer sub = 0;
            List<FullClassRate> classFullRateList = new ArrayList<FullClassRate>();
            List<CourseClass> oneProductClassList = productClassMap.get(product.getProductId());
            if (oneProductClassList == null) {
                fullClassRate.setRate(0);
                fullClassRate.setAll(0);
                fullClassRate.setSub(0);
                productFullClassRateList.add(fullClassRate);
                continue;
            }
            for (CourseClass courseClass : oneProductClassList) {
                Integer regNum = map.get(courseClass.getClassId());
                FullClassRate classFullRate = new FullClassRate();
                classFullRate.setName(courseClass.getClassName());
                classFullRate.setId(courseClass.getClassId());
                Integer classAll = courseClass.getQuota();
                Integer classSub = 0;
                all = all + classAll;
                if (regNum != null && product.getProductId().equals(courseClass.getProductId())) {
                    sub = sub + regNum;
                    classSub = classSub + regNum;
                    double classRate = 0.0;
                    if (classAll != 0) {
                        classRate = Double.parseDouble(df.format(((double) classSub / (double) classAll * 100)));
                    }
                    classFullRate.setAll(classAll);
                    classFullRate.setSub(classSub);
                    classFullRate.setRate(classRate);
                    classFullRateList.add(classFullRate);
                } else {

                    classFullRate.setAll(classAll);
                    classFullRate.setSub(0);
                    classFullRate.setRate(0);
                    classFullRateList.add(classFullRate);
                }
            }
            double rate = 0.0;
            if (all != 0) {
                rate = Double.parseDouble(df.format(((double) sub / (double) all * 100)));
            }
            fullClassRate.setAll(all);
            fullClassRate.setSub(sub);
            fullClassRate.setRate(rate);
            fullClassRate.setClassFullRateList(classFullRateList);
            productFullClassRateList.add(fullClassRate);

        }
        resultMap.put("gradeFullClassRateList", gradeFullClassRateList);
        resultMap.put("productFullClassRateList", productFullClassRateList);
        return resultMap;
    }

    private void renoveForbiddenClass(List<CourseClass> courseClasses,Long areaTeamId){
        Map<String,String> forbidClassPropMap = this.getFullClassForbidSettingMap(areaTeamId);
        List<Long> productIds = Utils.toLongIds(forbidClassPropMap.get("productIds"));
        List<Long> gradeIds = Utils.toLongIds(forbidClassPropMap.get("gradeIds"));
        List<Long> subjectIds = Utils.toLongIds(forbidClassPropMap.get("subjectIds"));
        List<Long> levels = Utils.toLongIds(forbidClassPropMap.get("levels"));
        Iterator<CourseClass> it = courseClasses.iterator();
        while (it.hasNext()){
            CourseClass courseClass = it.next();
            if (productIds.contains(courseClass.getProductId()) || gradeIds.contains(courseClass.getGradeId()) ||
                    subjectIds.contains(courseClass.getSubjectId()) || levels.contains(Long.valueOf(courseClass.getLevel()))){
                it.remove();
            }
        }
    }

    @Override
    public List<BusTeamFullClassRate> findBusTeamFullClassRate( List<Long> busTeamIds , List<Long> periodIds,List<Long> gradeIds ,List<Long> subjectIds,Long areaTeamId) {
        if (busTeamIds==null || busTeamIds.size()<=0 || periodIds==null ||periodIds.size()<=0 ){
            return Collections.EMPTY_LIST;
        }
        List<BusTeam> busTeamList=busTeamService.findByIds(busTeamIds);
        List<Period> periodList=periodService.findByIds(periodIds);
        List<BusTeamFullClassRate> busTeamFullClassRateList=new ArrayList<>();

        List<PeriodSegment> periodSegmentList=periodSegmentService.findByPeriodSegmentListByPeriodIds(periodIds);
        Map<Long,Map<Integer,PeriodSegment>> periodSegmentMap=periodSegmentService.periodSegmentToMapGroup(periodSegmentList);



        /*报名中和已结课的课程*/
        CourseClassQueryVo courseClassQueryVo=new CourseClassQueryVo();
        courseClassQueryVo.setBusTeamIds(busTeamIds);
        courseClassQueryVo.setSubjectIds(subjectIds);
        List<CourseClass> courseClassList = courseClassService.
                findListByBusTeamIdsPeriodIdsGradeIdsStatuses(busTeamIds, periodIds, gradeIds,Arrays.asList(1,3),
                        "periodId","periodName","classId","className", "busTeamId","busTeamName",
                        "gradeId","gradeName", "subjectId","subjectName" ,"quota", "lectureAmount","productId","level","classNo","teacherId","teacherName","roomId");
        // 移除禁止的班级
        renoveForbiddenClass(courseClassList,areaTeamId);
        Map<Long,List<CourseClass>> busClassMap=BeanUtils.toGroup(courseClassList,"busTeamId");

        List<Long> roomIds = Utils.unique(BeanUtils.toList(courseClassList, "roomId"));
        List<Room> roomList=roomService.findByIds(roomIds,"roomId","seatAmount");
        Map<Long, Room> roomMap = BeanUtils.toMap(roomList, "roomId");

        List<BaseGrade> baseGradeList=baseGradeService.findAllFromCache();

        PeriodQueryRegVo periodQueryRegVo=new PeriodQueryRegVo();
        periodQueryRegVo.setSubjectIds(subjectIds);
        periodQueryRegVo.setRegStatus(0);

        List<MergeStudentRegDetail> mergeStudentRegDetailList=mergeStudentRegDetailService.findListByBusTeamIdsPeriodsGradeIds(busTeamIds,periodIds,gradeIds,periodQueryRegVo,"classId","lectureNum","segmentNo","periodId");
        mergeStudentRegDetailList=mergeStudentRegDetailService.filterRegByEffectiveLectureNum(mergeStudentRegDetailList,periodSegmentMap);
        mergeStudentRegDetailList=mergeStudentRegDetailService.filteRegByReportConfig(periodIds,mergeStudentRegDetailList,ReportResourceEnum.满班率.id);
        Map<Long,ClassBigRegNum> regDetailMap=new HashMap<>();
        for (MergeStudentRegDetail mergeStudentRegDetail:mergeStudentRegDetailList){
            ClassBigRegNum classBigRegNum=regDetailMap.get(mergeStudentRegDetail.getClassId());
            if (classBigRegNum==null){
                classBigRegNum=new ClassBigRegNum();
                classBigRegNum.setClassId(mergeStudentRegDetail.getClassId());
                regDetailMap.put(mergeStudentRegDetail.getClassId(),classBigRegNum);
            }
            classBigRegNum.setRegNum((classBigRegNum.getRegNum()==null?0:classBigRegNum.getRegNum())+1);
        }

        Map<Long, List<MergeStudentRegDetail>> classRegMap = BeanUtils.toGroup(mergeStudentRegDetailList, "classId");

      /*  List<ClassBigRegNum> classBigRegNumList=mergeStudentRegDetailService.countBigRegNumByClassId(busTeamIds,periodIds,gradeIds,subjectIds,5);
*/
        //Map<Long,ClassBigRegNum> regDetailMap=BeanUtils.toMap(classBigRegNumList,"classId");
        List<MainAccountTarget> mainAccountTargetList=mainAccountTargetService.findListByMainAccountIdsAndPeriodIdsLikeTypes(busTeamIds,periodIds,null,"66");
        Map<Long,List<MainAccountTarget>> map=BeanUtils.toGroup(mainAccountTargetList,"mainAccountId");
        for (BusTeam busTeam:busTeamList){
            List<CourseClass> oneBusTeamClassList=busClassMap.get(busTeam.getBusTeamId());
            List<MainAccountTarget> oneBusTeamMainAccountTarget=map.get(busTeam.getBusTeamId());
            Map<Long,List<MainAccountTarget>> oneBusPeriodTargetMap=BeanUtils.toGroup(oneBusTeamMainAccountTarget,"periodId");
            Map<Long,List<CourseClass>> oneBusPeriodClassMap=BeanUtils.toGroup(oneBusTeamClassList,"periodId");
            for (Period period:periodList){
                List<MainAccountTarget> oneBusPeriodTargetList=oneBusPeriodTargetMap.get(period.getPeriodId());
                Map<Long,MainAccountTarget> mainAccountTargetMap=BeanUtils.toMap(oneBusPeriodTargetList,"groupId");

                List<CourseClass> oneBusPeriodClassList = oneBusPeriodClassMap.get(period.getPeriodId());
                Map<Long,List<CourseClass>> oneBusPeriodGradeClassMap=BeanUtils.toGroup(oneBusPeriodClassList,"gradeId");
                for (BaseGrade baseGrade:baseGradeList){


                    List<CourseClass> oneBusPeriodGradeClassList = oneBusPeriodGradeClassMap.get(baseGrade.getGradeId());
                    if (oneBusPeriodGradeClassList==null){
                        continue;
                    }
                    BusTeamFullClassRate busTeamFullClassRate=new BusTeamFullClassRate();
                    busTeamFullClassRate.setBusTeamId(busTeam.getBusTeamId());
                    busTeamFullClassRate.setBusTeamName(busTeam.getName());
                    busTeamFullClassRate.setPeriodId(period.getPeriodId());
                    busTeamFullClassRate.setPeriodName(period.getPeriodName());
                    busTeamFullClassRate.setGradeId(baseGrade.getGradeId());
                    busTeamFullClassRate.setGradeName(baseGrade.getGradeName());
                    Integer totalQuota=0;
                    Integer totalEffectiveRegAmount=0;
                    List<ClassFullRate> classFullRateList=new ArrayList<>(oneBusPeriodClassList.size());
                    for (CourseClass courseClass:oneBusPeriodGradeClassList){
                        ClassBigRegNum classBigRegNum=regDetailMap.get(courseClass.getClassId());
                        Integer effectiveRegAmount=classBigRegNum==null?0:classBigRegNum.getRegNum()==null?0:classBigRegNum.getRegNum();
                        ClassFullRate classFullRate=new ClassFullRate();
                        totalEffectiveRegAmount=totalEffectiveRegAmount+effectiveRegAmount;
                        Room room=roomMap.get(courseClass.getRoomId());
                        Integer seatAmount=28;
                        if (room!=null && room.getSeatAmount()!=null){
                            seatAmount=room.getSeatAmount();
                        }
                        totalQuota=totalQuota+seatAmount;

                        BeanUtils.copyProperties(classFullRate,courseClass);
                        classFullRate.setEffectiveRegAmount(effectiveRegAmount);
                        classFullRate.setQuota(seatAmount);
                        classFullRate.setFullClassRate(Utils.getPercent(classFullRate.getEffectiveRegAmount().toString(),classFullRate.getQuota().toString(),2));
                        classFullRateList.add(classFullRate);
                    }
                    busTeamFullClassRate.setTotalQuota(totalQuota);
                    busTeamFullClassRate.setTotalEffectiveRegAmount(totalEffectiveRegAmount);
                    busTeamFullClassRate.setBusTeamFullClassRate(Utils.getPercent(busTeamFullClassRate.getTotalEffectiveRegAmount().toString(),busTeamFullClassRate.getTotalQuota().toString(),2));
                    busTeamFullClassRate.setClassFullRateList(classFullRateList);

                    MainAccountTarget mainAccountTarget=mainAccountTargetMap.get(baseGrade.getGradeId());
                    if (mainAccountTarget!=null){
                        busTeamFullClassRate.setTargetFullClassRate(mainAccountTarget.getTargetNum());
                    }

                    busTeamFullClassRateList.add(busTeamFullClassRate);


                }


            }
        }

        return busTeamFullClassRateList;
    }




    @Override
    public SXSSFWorkbook exportBusTeamFullClassRate(List<Long> busTeamIds, List<Long> periodIds,List<Long> gradeIds,Long areaTeamId) {
        List<BusTeamFullClassRate> busTeamFullClassRateList=this.findBusTeamFullClassRate(busTeamIds,periodIds,gradeIds,null,areaTeamId);

        return busTeamFullClassRate2excel(busTeamFullClassRateList);
    }

    @Override
    public List<AreaTeamFullClassRate> findAreaTeamFullClassRate(Long areaTeamId,List<Long> busTeamIds, List<Long> periodIds,List<Long> gradeIds,List<Long> subjectIds) {
        List<AreaTeamFullClassRate> areaTeamFullClassRates=new ArrayList<>();
        List<BaseGrade> baseGradeList=null;
        if (Utils.checkListEmpty(gradeIds)){
            baseGradeList=baseGradeService.findAllOrderGrade();
        }else {
            baseGradeList=baseGradeService.findDealOtherPosition(gradeIds);
        }
        AreaTeam areaTeam=areaTeamService.findById(areaTeamId);
        AreaTeamFullClassRate areaTeamFullClassRate=new AreaTeamFullClassRate();
        areaTeamFullClassRate.setAreaTeamId(areaTeamId);
        areaTeamFullClassRate.setAreaTeamName(areaTeam.getName());

        List<Period> periodList=periodService.findByIds(periodIds);
        List<Long> withPeriodIds=BeanUtils.toList(periodList,"withPeriodId");
        List<Period> withPeriodList=periodService.findByIds(withPeriodIds);
        Map<Long,Period> withPeriodMap=BeanUtils.toMap(withPeriodList,"periodId");
        List<Long> allPeriodIds=new ArrayList<>();
        allPeriodIds.addAll(periodIds);
        if (Utils.checkListNotEmpty(withPeriodIds)){
            allPeriodIds.addAll(withPeriodIds);
        }

        allPeriodIds=Utils.removeDuplicate(allPeriodIds);
        List<BusTeamFullClassRate> busTeamFullClassRateList=this.findBusTeamFullClassRate(busTeamIds,allPeriodIds,gradeIds,subjectIds,areaTeamId);

        Map<Long,List<BusTeamFullClassRate>> map=BeanUtils.toGroup(busTeamFullClassRateList,"periodId");

        for (Period period:periodList){
            Period withPeriod=withPeriodMap.get(period.getWithPeriodId());

            areaTeamFullClassRate.setPeriodId(period.getPeriodId());
            areaTeamFullClassRate.setPeriodName(period.getPeriodName());
            areaTeamFullClassRate.setWithPeriodId(period.getWithPeriodId());
            areaTeamFullClassRate.setWithPeriodName(withPeriod== null ? "" : withPeriod.getPeriodName());

            List<BusTeamFullClassRate> nowBusTeamFullClassRateList = map.get(period.getPeriodId());
            List<BusTeamFullClassRate> withBusTeamFullClassRateList = map.get(period.getWithPeriodId());
            Map<Long, List<BusTeamFullClassRate>> nowBusTeamGradeFullClassRateMap = BeanUtils.toGroup(nowBusTeamFullClassRateList, "gradeId");
            Map<Long, List<BusTeamFullClassRate>> withBusTeamGradeFullClassRateMap = BeanUtils.toGroup(withBusTeamFullClassRateList, "gradeId");
            List<GradeFullClassRate> gradeFullClassRateList=new ArrayList<>(baseGradeList.size());
            for (BaseGrade baseGrade : baseGradeList) {
                GradeFullClassRate gradeFullClassRate = new GradeFullClassRate();
                gradeFullClassRate.setGradeId(baseGrade.getGradeId());
                gradeFullClassRate.setGradeName(baseGrade.getGradeName());

                List<BusTeamFullClassRate> nowBusTeamGradeFullClassRateList = nowBusTeamGradeFullClassRateMap.get(baseGrade.getGradeId());
                List<BusTeamFullClassRate> withBusTeamGradeFullClassRateList = withBusTeamGradeFullClassRateMap.get(baseGrade.getGradeId());

                if (nowBusTeamGradeFullClassRateList != null) {
                    for (BusTeamFullClassRate busTeamFullClassRate : nowBusTeamGradeFullClassRateList) {
                        gradeFullClassRate.setGradeQuota(busTeamFullClassRate.getTotalQuota() + gradeFullClassRate.getGradeQuota());
                        gradeFullClassRate.setGradeEffectiveRegAmount(busTeamFullClassRate.getTotalEffectiveRegAmount() + gradeFullClassRate.getGradeEffectiveRegAmount());
                    }
                    areaTeamFullClassRate.setAreaTeamQuota(areaTeamFullClassRate.getAreaTeamQuota() + gradeFullClassRate.getGradeQuota());
                    areaTeamFullClassRate.setAreaTeamEffectiveRegAmount(areaTeamFullClassRate.getAreaTeamEffectiveRegAmount() + gradeFullClassRate.getGradeEffectiveRegAmount());
                    gradeFullClassRate.setTotalFullClassRate(Utils.getPercent(gradeFullClassRate.getGradeEffectiveRegAmount().toString(), gradeFullClassRate.getGradeQuota().toString(), 2));
                }
                if (withBusTeamGradeFullClassRateList != null) {
                    for (BusTeamFullClassRate busTeamFullClassRate : withBusTeamGradeFullClassRateList) {
                        gradeFullClassRate.setWithGradeQuota(busTeamFullClassRate.getTotalQuota() + gradeFullClassRate.getWithGradeQuota());
                        gradeFullClassRate.setWithGradeEffectiveRegAmount(busTeamFullClassRate.getTotalEffectiveRegAmount() + gradeFullClassRate.getWithGradeEffectiveRegAmount());
                    }
                    areaTeamFullClassRate.setWithAreaTeamEffectiveRegAmount(areaTeamFullClassRate.getWithAreaTeamEffectiveRegAmount() + gradeFullClassRate.getWithGradeEffectiveRegAmount());
                    areaTeamFullClassRate.setWithAreaTeamQuota(areaTeamFullClassRate.getWithAreaTeamQuota() + gradeFullClassRate.getWithGradeQuota());
                    gradeFullClassRate.setWithTotalFullClassRate(Utils.getPercent(gradeFullClassRate.getWithGradeEffectiveRegAmount().toString(), gradeFullClassRate.getWithGradeQuota().toString(), 2));
                }
                gradeFullClassRateList.add(gradeFullClassRate);
            }
            areaTeamFullClassRate.setTotalFullClassRate(Utils.getPercent(areaTeamFullClassRate.getAreaTeamEffectiveRegAmount().toString(),areaTeamFullClassRate.getAreaTeamQuota().toString(),2));
            areaTeamFullClassRate.setWithTotalFullClassRate(Utils.getPercent(areaTeamFullClassRate.getWithAreaTeamEffectiveRegAmount().toString(),areaTeamFullClassRate.getWithAreaTeamQuota().toString(),2));
            areaTeamFullClassRate.setGradeFullClassRateList(gradeFullClassRateList);
            areaTeamFullClassRates.add(areaTeamFullClassRate);
        }



        return areaTeamFullClassRates;
    }

    @Override
    @Cacheable(value = "CacheOfBusTeamPeriodClassRegNum",key = "#areaTeamId+'_'+#busTeamId+'_'+#periodId")
    public BusTeamPeriodClassRegNumVo findBusTeamPeriodClassRegNumVo(long areaTeamId, long busTeamId, long periodId) {
        BusTeamPeriodClassRegNumVo busTeamPeriodClassRegNumVo=new BusTeamPeriodClassRegNumVo();
        busTeamPeriodClassRegNumVo.setBusTeamId(busTeamId);
        busTeamPeriodClassRegNumVo.setPeriodId(periodId);

        List<AreaTeamFullClassRate> areaTeamFullClassRateList = this.findAreaTeamFullClassRate(areaTeamId, Arrays.asList(busTeamId), Arrays.asList(periodId), null, null);


        BusTeamPeriodSeqStepNumVo busTeamPeriodSeqStepNumVo=new BusTeamPeriodSeqStepNumVo();
        busTeamPeriodSeqStepNumVo.setBusTeamId(busTeamId);
        busTeamPeriodSeqStepNumVo.setPeriodId(periodId);

        if (Utils.checkListNotEmpty(areaTeamFullClassRateList)){
            for (AreaTeamFullClassRate areaTeamFullClassRate:areaTeamFullClassRateList){
                busTeamPeriodClassRegNumVo.setWithPeriodId(areaTeamFullClassRate.getWithPeriodId());
                busTeamPeriodClassRegNumVo.setBusTeamQuota(busTeamPeriodClassRegNumVo.getBusTeamQuota()+areaTeamFullClassRate.getAreaTeamQuota());
                busTeamPeriodClassRegNumVo.setBusTeamEffectiveRegAmount(busTeamPeriodClassRegNumVo.getBusTeamEffectiveRegAmount()+areaTeamFullClassRate.getAreaTeamEffectiveRegAmount());
                busTeamPeriodClassRegNumVo.setWithBusTeamQuota(busTeamPeriodClassRegNumVo.getWithBusTeamQuota()+areaTeamFullClassRate.getWithAreaTeamQuota());
                busTeamPeriodClassRegNumVo.setWithBusTeamEffectiveRegAmount(busTeamPeriodClassRegNumVo.getWithBusTeamEffectiveRegAmount()+areaTeamFullClassRate.getWithAreaTeamEffectiveRegAmount());
            }
        }
        return busTeamPeriodClassRegNumVo;
    }

    public static SXSSFWorkbook busTeamFullClassRate2excel(List<BusTeamFullClassRate> busTeamFullClassRateList) {
        SXSSFWorkbook excel = new SXSSFWorkbook();
        SXSSFSheet sheet = excel.createSheet("业务组满班率");
        SXSSFRow firstRow = sheet.createRow(0);
        String[] titles = new String[]{"业务组","期数","年级","有效报名数","总学位数","满班率"};
        for (int i = 0; i < titles.length; i++) {
            firstRow.createCell(i).setCellValue(titles[i]);
        }

        SXSSFSheet classSheet = excel.createSheet("班级满班率");
        SXSSFRow classFirstRow = classSheet.createRow(0);
        String[] classTitles = new String[]{"业务组","期数","班级名称","班级编号","任课老师","年级","科目","有效报名数","学位数","满班率"};
        for (int i = 0; i < classTitles.length; i++) {
            classFirstRow.createCell(i).setCellValue(classTitles[i]);
        }
        int rowNum=1;
        int classRowNum=1;
        for (BusTeamFullClassRate busTeamFullClassRate:busTeamFullClassRateList){
            int cellNum = 0;
            SXSSFRow row = sheet.createRow(rowNum++);

            SXSSFCell cell = row.createCell(cellNum++);
            cell.setCellValue(StringUtils.defaultString(busTeamFullClassRate.getBusTeamName()));

            cell = row.createCell(cellNum++);
            cell.setCellValue(StringUtils.defaultString(busTeamFullClassRate.getPeriodName()));

            cell = row.createCell(cellNum++);
            cell.setCellValue(StringUtils.defaultString(busTeamFullClassRate.getGradeName()));


            cell = row.createCell(cellNum++);
            cell.setCellValue(busTeamFullClassRate.getTotalEffectiveRegAmount()==null?0:busTeamFullClassRate.getTotalEffectiveRegAmount());

            cell = row.createCell(cellNum++);
            cell.setCellValue(busTeamFullClassRate.getTotalQuota()==null?0:busTeamFullClassRate.getTotalQuota());

            cell = row.createCell(cellNum++);
            cell.setCellValue(StringUtils.defaultString(busTeamFullClassRate.getBusTeamFullClassRate()));

            List<ClassFullRate> classFullRateList=busTeamFullClassRate.getClassFullRateList();
            if (classFullRateList!=null){
                classSheet=toClassFullSheet(classSheet,classRowNum,classFullRateList);
                classRowNum=classRowNum+classFullRateList.size();
            }
        }
        return excel;
    }

    private  static  SXSSFSheet toClassFullSheet(SXSSFSheet sheet,int rowNum,List<ClassFullRate> classFullRateList){
        if (classFullRateList!=null){
            for (ClassFullRate classFullRate:classFullRateList){
                int cellNum=0;
                SXSSFRow classRow = sheet.createRow(rowNum++);
                SXSSFCell cell = classRow.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classFullRate.getBusTeamName()));

                cell = classRow.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classFullRate.getPeriodName()));

                cell = classRow.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classFullRate.getClassName()));

                cell = classRow.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classFullRate.getClassNo()));

                cell = classRow.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classFullRate.getTeacherName()));

                cell = classRow.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classFullRate.getGradeName()));

                cell = classRow.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classFullRate.getSubjectName()));

                cell = classRow.createCell(cellNum++);
                cell.setCellValue(classFullRate.getEffectiveRegAmount()==null?0:classFullRate.getEffectiveRegAmount());

                cell = classRow.createCell(cellNum++);
                cell.setCellValue(classFullRate.getQuota()==null?0:classFullRate.getQuota());

                cell = classRow.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classFullRate.getFullClassRate()));
            }

        }
        return sheet;
    }

    @Override
    public Page<ClassAvgRegVo> findClassAvgReg(DataPermission dataPermission,SimpleQueryVo simpleQueryVo, int pageNo, int pageSize) {
        if (Utils.checkListEmpty(simpleQueryVo.getBusTeamIds())){
            simpleQueryVo.setBusTeamIds(simpleQueryVo.getBusTeamIds());
        }
        Page<ClassAvgRegVo> page=new Page<>(pageNo,pageSize);
        List<BusTeamPeriodGradeClassNumVo> busTeamPeriodGradeClassNumVoList=courseClassService.findBusTeamPeriodGradeClassNum(simpleQueryVo,(pageNo-1)*pageSize,pageSize);
        Integer total=courseClassService.countBusTeamPeriodGradeClassNum(simpleQueryVo);
        page.setTotal(total);
        List<BusTeamPeriodGradeRegNumVo> busTeamPeriodGradeRegNumVoList=mergeStudentRegDetailService.findBusTeamPeriodGradeRegNum(simpleQueryVo,(pageNo-1)*pageSize,pageSize);
        Map<String,BusTeamPeriodGradeRegNumVo> map=new HashMap<>();
        if (busTeamPeriodGradeRegNumVoList!=null){
            for (BusTeamPeriodGradeRegNumVo busTeamPeriodGradeRegNumVo:busTeamPeriodGradeRegNumVoList){
                String key=busTeamPeriodGradeRegNumVo.getBusTeamId()+"_"+busTeamPeriodGradeRegNumVo.getPeriodId()+"_"+busTeamPeriodGradeRegNumVo.getGradeId();
                map.put(key,busTeamPeriodGradeRegNumVo);
            }

        }
        if (busTeamPeriodGradeClassNumVoList!=null){
            List<ClassAvgRegVo> classAvgRegVoList=new ArrayList<>(busTeamPeriodGradeClassNumVoList.size());
            for (BusTeamPeriodGradeClassNumVo busTeamPeriodGradeClassNumVo:busTeamPeriodGradeClassNumVoList){
                ClassAvgRegVo classAvgRegVo=new ClassAvgRegVo();
                BeanUtils.copyProperties(classAvgRegVo,busTeamPeriodGradeClassNumVo);
                String key=busTeamPeriodGradeClassNumVo.getBusTeamId()+"_"+busTeamPeriodGradeClassNumVo.getPeriodId()+"_"+busTeamPeriodGradeClassNumVo.getGradeId();
                BusTeamPeriodGradeRegNumVo busTeamPeriodGradeRegNumVo=map.get(key);
                if (busTeamPeriodGradeRegNumVo!=null){
                    classAvgRegVo.setRegNum(busTeamPeriodGradeRegNumVo.getRegNum());
                    classAvgRegVo.setClassAvgReg(Utils.roundByDouble(busTeamPeriodGradeRegNumVo.getRegNum().doubleValue()/busTeamPeriodGradeClassNumVo.getClassNum(),2));
                }else {
                    classAvgRegVo.setRegNum(0);
                    classAvgRegVo.setClassAvgReg(0d);
                }
                classAvgRegVoList.add(classAvgRegVo);
            }
            page.setRecords(classAvgRegVoList);
        }
        return page;
    }

    @Override
    public SXSSFWorkbook exportClassAvgReg(DataPermission dataPermission, SimpleQueryVo simpleQueryVo) {
        return classAvgReg2excel(this.findClassAvgReg(dataPermission,simpleQueryVo,1,10000).getRecords());
    }

    public static SXSSFWorkbook classAvgReg2excel(List<ClassAvgRegVo> classAvgRegVoList) {
        SXSSFWorkbook excel = new SXSSFWorkbook();
        SXSSFSheet sheet = excel.createSheet("班均");
        SXSSFRow firstRow = sheet.createRow(0);
        String[] titles = new String[]{"业务组","期数","年级","总科数","开班数","班均"};
        for (int i = 0; i < titles.length; i++) {
            firstRow.createCell(i).setCellValue(titles[i]);
        }

        int rowNum=1;
        if (classAvgRegVoList!=null){
            for (ClassAvgRegVo classAvgRegVo:classAvgRegVoList){
                int cellNum = 0;
                SXSSFRow row = sheet.createRow(rowNum++);

                SXSSFCell cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classAvgRegVo.getBusTeamName()));

                cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classAvgRegVo.getPeriodName()));

                cell = row.createCell(cellNum++);
                cell.setCellValue(StringUtils.defaultString(classAvgRegVo.getGradeName()));


                cell = row.createCell(cellNum++);
                cell.setCellType(CellType.NUMERIC);
                cell.setCellValue(classAvgRegVo.getRegNum());

                cell = row.createCell(cellNum++);
                cell.setCellType(CellType.NUMERIC);
                cell.setCellValue(classAvgRegVo.getClassNum());

                cell = row.createCell(cellNum++);
                cell.setCellValue(classAvgRegVo.getClassAvgReg());

            }
        }

        return excel;
    }

    @Override
    public void fullClassForbidSetting(ClassForbiddenPropertiesVo classForbiddenPropertiesVo,Long areaTeamId) {
        String key = String.format(FULLCLASS_FORBID_SETTING,areaTeamId);
        Map<String,String> map = JSONObject.parseObject(
                JSONObject.toJSONString(classForbiddenPropertiesVo),new TypeReference<Map<String,String>>(){});
        redisTemplate.delete(key);
        redisTemplate.opsForHash().putAll(key,map);
    }

    @Override
    public Map<String, String> getFullClassForbidSettingMap(Long areaTeamId) {
        String key = String.format(FULLCLASS_FORBID_SETTING,areaTeamId);
        HashOperations<String,String,String> hashOperations = redisTemplate.opsForHash();
        Map<String,String> forbiddenMap = hashOperations.entries(key);
        return forbiddenMap;
    }
}